home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / umddvi / lib / font.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  9KB  |  418 lines

  1. /*
  2.  * Copyright (c) 1987 University of Maryland Department of Computer Science.
  3.  * All rights reserved.  Permission to copy for any purpose is hereby granted
  4.  * so long as this copyright notice remains intact.
  5.  */
  6.  
  7. #ifndef lint
  8. static char rcsid[] = "$Header: font.c,v 2.6 87/06/16 18:27:56 chris Exp $";
  9. #endif
  10.  
  11. /*
  12.  * Routines for working with fonts.  In particular, the configuration
  13.  * dependent code is here.
  14.  *
  15.  * Specific fonts (GF, PXL, etc.) have functions in separate files.
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <errno.h>
  20. #include "types.h"
  21. #include "conv.h"
  22. #include "font.h"
  23.  
  24. /*
  25.  * Define the default configuration file.
  26.  * Also define the maximum path name length.
  27.  */
  28. #ifndef CONFFILE
  29. #define CONFFILE "/usr/local/lib/tex/fontdesc"
  30. #endif
  31.  
  32. #define    PATHLEN    1024
  33.  
  34. /*
  35.  * A font configuration.  The font list is ordered.
  36.  *
  37.  * A specifier is typically a particular print engine, since
  38.  * different engines need slightly different fonts.
  39.  */
  40. struct fontconf {
  41.     struct    fontconf *fc_next;
  42.     struct    fontops *fc_ops;
  43.     char    *fc_path;    /* path, with metacharacters */
  44.     char    *fc_spec;    /* specifier */
  45.     int    fc_slop;    /* slop value */
  46. };
  47.  
  48. /*
  49.  * EQ is a fast way to check for string equivalence.
  50.  */
  51. #define    EQ(a, b) (*(a) == *(b) && strcmp(a, b) == 0)
  52.  
  53. /*
  54.  * Private variables.
  55.  */
  56. static    int didinit;        /* true => initialised already */
  57. static    char *cfname;        /* config file name, for errors */
  58. static    int cfline;        /* config file line, likewise */
  59. static    struct fontops *fontops;/* font operations code: list head */
  60. static    struct fontconf *fonts;    /* font list */
  61. static    struct fontconf **nextfc;/* used during initialisation */
  62. static    char spec_any[] = "*";    /* the `anything' specifier */
  63.  
  64. /*
  65.  * Imports.
  66.  */
  67. extern    int errno;
  68. char    *getenv(), *malloc(), *strsave();
  69. #ifndef sys5
  70. char    *sprintf();
  71. #endif
  72.  
  73. /*
  74.  * Here, alas, we know about all the kinds of fonts.
  75.  * This also means that every DVI interpreter pulls in
  76.  * the full set of font manipulation routines.
  77.  *
  78.  * PERHAPS THIS SHOULD BE CONFIGURABLE.
  79.  */
  80. #define    ADDFONT(x) { \
  81.     extern struct fontops x; \
  82.     x.fo_next = fontops; \
  83.     fontops = &x; \
  84. }
  85.  
  86. fontinit(file)
  87.     char *file;
  88. {
  89.  
  90.     if (didinit) {
  91.         /*
  92.          * Could free the old configuration and fire up
  93.          * a new one, but for now . . .
  94.          */
  95.         error(1, 0, "attempt to reinit fonts");
  96.         /* NOTREACHED */
  97.     }
  98.     didinit++;
  99.     ADDFONT(boxops);
  100.     ADDFONT(blankops);
  101.     ADDFONT(invisops);
  102.     ADDFONT(pxlops);
  103.     ADDFONT(pkops);
  104.     ADDFONT(gfops);
  105.     nextfc = &fonts;
  106.     if (file == NULL)
  107.         if ((file = getenv(CONFENV)) == NULL)
  108.             file = CONFFILE;
  109.     readconf(file);
  110. }
  111.  
  112. /*
  113.  * A proto resembles a fontspec (indeed, it is a prototype
  114.  * fontspec) but is not quite the same.  It is used to gather
  115.  * the information needed per fontspec before allocating
  116.  * the fontspec itself.
  117.  */
  118. struct proto {
  119.     char    *p_type;
  120.     char    *p_spec;
  121.     char    *p_slop;
  122.     char    *p_path;
  123. };
  124.  
  125. /*
  126.  * Read the named configuration file.  The file is split into
  127.  * lines, and lines are split into words; if the first word is
  128.  * "font", this is a fontconf, and we read the remainder of the
  129.  * words and make a fontconf entry.
  130.  */
  131. static
  132. readconf(name)
  133.     char *name;
  134. {
  135.     register FILE *f;    /* config file */
  136.     register char **p;    /* pointer into word vector */
  137.     register int c;
  138.     char line[1024];    /* input line */
  139.     char *v[100];        /* word vector */
  140.     struct proto proto;    /* prototype fontconf */
  141.  
  142. #define GETWORD(x, ifnone) \
  143.     if (--c <= 0) \
  144.         badcf(ifnone); \
  145.     else \
  146.         (x) = *p++
  147.  
  148.     if ((f = fopen(name, "r")) == NULL)
  149.         error(1, errno, "cannot read font configuration file \"\%s\"",
  150.             name);
  151.     cfname = name;
  152.     cfline = 0;
  153.     while (fgets(line, sizeof (line), f) != NULL) {
  154.         cfline++;
  155.         if ((c = strlen(line)) > 0) {
  156.             if (line[--c] != '\n')
  157.                 badcf("line too long");
  158.             line[c] = 0;
  159.         }
  160.         if ((c = split(line, v, sizeof (v) / sizeof (*v))) < 0)
  161.             badcf("too many words");
  162.         p = v;
  163.         /* skip things that are not fonts */
  164.         if (c == 0 || !EQ(*p, "font"))
  165.             continue;
  166.         p++;
  167.         GETWORD(proto.p_type, "missing font typename");
  168.         GETWORD(proto.p_spec, "missing font spec (engine)");
  169.         GETWORD(proto.p_slop, "missing slop value");
  170.         GETWORD(proto.p_path, "need pathname");
  171.         (void) setfont(&proto);
  172.     }
  173. }
  174.  
  175. /*
  176.  * Find a font's operations, given its name.
  177.  */
  178. static struct fontops *
  179. findops(name)
  180.     register char *name;
  181. {
  182.     register struct fontops *fo;
  183.  
  184.     for (fo = fontops; fo != NULL; fo = fo->fo_next)
  185.         if (EQ(fo->fo_name, name))
  186.             return (fo);
  187.     return (NULL);
  188. }
  189.  
  190. /*
  191.  * Turn a prototype fontconf into a real one.
  192.  */
  193. static int
  194. setfont(p)
  195.     register struct proto *p;
  196. {
  197.     register struct fontconf *fc;
  198.     struct fontops *ops = findops(p->p_type);
  199.  
  200.     if (ops == NULL) {
  201.         error(0, 0,
  202.             "\"%s\", line %d: unknown font type \"%s\" ignored",
  203.             cfname, cfline, p->p_type);
  204.         return (-1);
  205.     }
  206.     if ((fc = (struct fontconf *) malloc(sizeof (*fc))) == NULL)
  207.         error(1, errno,
  208.             "out of memory for font configuration (sorry)");
  209.     fc->fc_ops = ops;
  210.     fc->fc_next = NULL;
  211.     fc->fc_path = strsave(p->p_path);
  212.     fc->fc_spec = EQ(p->p_spec, spec_any) ? NULL : strsave(p->p_spec);
  213.     fc->fc_slop = atoi(p->p_slop);
  214.     if (fc->fc_slop < 1)    /* quietly enforce proper slops */
  215.         fc->fc_slop = 1;
  216.     *nextfc = fc;
  217.     nextfc = &fc->fc_next;
  218.     return (0);
  219. }
  220.  
  221. /*
  222.  * Complain about a problem in the configuration file.
  223.  */
  224. static
  225. badcf(why)
  226.     char *why;
  227. {
  228.  
  229.     error(1, 0, "\"%s\", line %d: %s", cfname, cfline, why);
  230.     /* NOTREACHED */
  231. }
  232.  
  233. /*
  234.  * Turn a prototype path, name, and magnification into a full
  235.  * path.
  236.  */
  237. static
  238. pave(result, proto, name, mag)
  239.     char *result, *proto, *name;
  240.     int mag;
  241. {
  242.     register int c;
  243.     register char *s, *d, *p;
  244.     char num[30];
  245.  
  246.     d = result;
  247.     p = proto;
  248.     s = NULL;
  249.     num[0] = 0;        /* will need changing for other bases */
  250.  
  251.     while (p != NULL) {
  252.         /*
  253.          * If sourcing from s, take its next character, and
  254.          * insert it directly.  Otherwise take the next path
  255.          * character and interpret it.
  256.          */
  257.         if (s != NULL) {
  258.             if ((c = *s++) == 0) {
  259.                 s = NULL;
  260.                 continue;
  261.             }
  262.             goto put;
  263.         }
  264.         if ((c = *p++) == 0)
  265.             p = NULL;
  266.         if (c != '%')
  267.             goto put;
  268.  
  269.         switch (c = *p++) {
  270.  
  271.         case 'f':
  272.         case 'n':
  273.         case 's':
  274.             s = name;
  275.             continue;
  276.  
  277.         case 'd':
  278.         case 'm':
  279.             if (num[0] == 0)
  280.                 (void) sprintf(num, "%d", mag);
  281.             s = num;
  282.             continue;
  283.  
  284.         case 0:
  285.             c = '%';
  286.             p--;
  287.             /* FALLTHROUGH */
  288.         }
  289. put:
  290.         if (d - result >= PATHLEN)
  291.             error(1, 0, "font path `%s' too long (sorry)", proto);
  292.         *d++ = c;
  293.     }
  294. }
  295.  
  296. struct font *getafont();    /* get a font and optional rasters */
  297.  
  298. /*
  299.  * Given a font name and size, return the first font that fits, along
  300.  * with its name (via fname).  If we cannot find such a font, we set
  301.  * *fname to point to a `canonical' example font name, unless there are
  302.  * are no fonts for the device, in which case we set *fname to NULL.
  303.  */
  304. struct font *
  305. GetFont(nm, dvimag, dvidsz, dev, fname)
  306.     char *nm;
  307.     i32 dvimag, dvidsz;
  308.     char *dev, **fname;
  309. {
  310.  
  311.     return (getafont(nm, dvimag, dvidsz, dev, fname, 1));
  312. }
  313.  
  314. /*
  315.  * Same as GetFont, but caller promises never to ask for rasters.
  316.  */
  317. struct font *
  318. GetRasterlessFont(nm, dvimag, dvidsz, dev, fname)
  319.     char *nm;
  320.     i32 dvimag, dvidsz;
  321.     char *dev, **fname;
  322. {
  323.  
  324.     return (getafont(nm, dvimag, dvidsz, dev, fname, 0));
  325. }
  326.  
  327. /*
  328.  * NEED TO THINK ABOUT gf NAMING CONVENTIONS HERE: ARE THEY LIKE pxl?
  329.  * WHAT ABOUT OTHERS?
  330.  */
  331. static struct font *
  332. getafont(nm, dvimag, dvidsz, dev, fname, wantrast)
  333.     char *nm;
  334.     i32 dvimag, dvidsz;
  335.     char *dev, **fname;
  336.     int wantrast;
  337. {
  338.     register int slop, fmag;
  339.     register struct font *f;
  340.     register struct fontconf *fc;
  341.     register char *path;
  342.     static char firstpath[PATHLEN], laterpath[PATHLEN];
  343.     double mag;
  344.     int scaled;
  345.  
  346.     if (!didinit)
  347.         fontinit((char *) NULL);
  348.  
  349.     /*
  350.      * The equation below means, approximately, `the font is
  351.      * magnified by the ratio of the actual size dvimag to the
  352.      * design size dvidsz, and then further scaled by the
  353.      * global magnification.'  We multiply this by the printer's
  354.      * resolution in dots per inch, then use the per-font
  355.      * conversion factor to convert a dots-per-inch value to
  356.      * a font name `%m' magnification (extension).
  357.      */
  358.     mag = (double) dvimag / (double) dvidsz;
  359.     scaled = mag * 1000.0 + 0.5;
  360.     mag *= Conversion.c_mag * Conversion.c_dpi;
  361.  
  362.     path = firstpath;
  363.     for (fc = fonts; fc != NULL; fc = fc->fc_next) {
  364.         if (dev != NULL && fc->fc_spec != NULL &&
  365.             !EQ(dev, fc->fc_spec))
  366.             continue;
  367.         fmag = mag * fc->fc_ops->fo_dpitomag + 0.5;
  368.         for (slop = 0; slop < fc->fc_slop; slop++) {
  369.             pave(path, fc->fc_path, nm, fmag + slop);
  370.             if (access(path, 4) == 0)
  371.                 goto found;
  372.             if (slop) {
  373.                 pave(path, fc->fc_path, nm, fmag - slop);
  374.                 if (access(path, 4) == 0)
  375.                     goto found;
  376.             }
  377.             path = laterpath;
  378.         }
  379.     }
  380.  
  381.     /* not found */
  382.     if (path == firstpath) {    /* never got to try any paths */
  383.         *fname = NULL;
  384.         errno = ENXIO;
  385.     } else {
  386.         *fname = firstpath;
  387.         errno = ENOENT;
  388.     }
  389.     return (NULL);
  390.  
  391. found:
  392.     *fname = path;
  393.  
  394.     /* allocate space for the per-font info, and read it in */
  395.     f = (struct font *) malloc(sizeof (struct font));
  396.     if (f == NULL)
  397.         return (NULL);
  398.     f->f_flags = wantrast ? FF_RASTERS : 0;
  399.     f->f_ops = fc->fc_ops;
  400.     f->f_path = strsave(path);
  401.     f->f_font = strsave(nm);
  402.     f->f_dvimag = dvimag;
  403.     f->f_dvidsz = dvidsz;
  404.     f->f_scaled = scaled;
  405.     f->f_checksum = 0;    /* in case the font reader cannot get one */
  406.     errno = 0;
  407.     if ((*f->f_ops->fo_read)(f)) {
  408.         int e = errno;    /* paranoid */
  409.  
  410.         free(f->f_path);
  411.         free(f->f_font);
  412.         free((char *) f);
  413.         errno = e;
  414.         return (NULL);
  415.     }
  416.     return (f);
  417. }
  418.